home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / b / b.lha / B / src / bed / gram.c < prev    next >
C/C++ Source or Header  |  1988-11-24  |  8KB  |  401 lines

  1. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  2. static char rcsid[] = "$Header: gram.c,v 2.5 85/08/22 16:03:16 timo Exp $";
  3.  
  4. /*
  5.  * B editor -- All routines referencing the grammar table are in this file.
  6.  */
  7.  
  8. #include "b.h"
  9. #include "feat.h"
  10. #include "bobj.h"
  11. #include "node.h"
  12. #include "gram.h"
  13. #include "supr.h"
  14. #include "tabl.h"
  15.  
  16. extern bool dflag;
  17.  
  18. #include <ctype.h>
  19.  
  20.  
  21. /*
  22.  * Test whether sym is in the given class.
  23.  */
  24.  
  25. Visible bool
  26. isinclass(sym, ci)
  27.     register int sym;
  28.     struct classinfo *ci;
  29. {
  30.     register classptr cp;
  31.  
  32.     Assert(ci && ci->c_class);
  33.     if (sym == Hole)
  34.         return !isinclass(Optional, ci);
  35.     for (cp = ci->c_class; *cp; ++cp)
  36.         if (sym == *cp)
  37.             return Yes;
  38.     return No;
  39. }
  40.  
  41.  
  42. /*
  43.  * Deliver the representation array for the given node.
  44.  * If the node is actually just a "text" value, construct
  45.  * one in static storage -- which is overwritten at each call.
  46.  * In this case there are two deficiencies: the next call to
  47.  * noderepr which uses the same feature overwrites the reply
  48.  * value of the previous call, AND if the text value itself
  49.  * is changed, the representation may change, too.
  50.  * In practical use this is no problem at all, however.
  51.  */
  52.  
  53. Visible string *
  54. noderepr(n)
  55.     register node n;
  56. {
  57.     register int sym;
  58.  
  59.     if (n && Type(n) == Tex) {
  60.         static string buf[2];
  61.         buf[0] = Str((value)n);
  62.         return buf;
  63.     }
  64.     sym = symbol(n);
  65.     return table[sym].r_repr;
  66. }
  67.  
  68.  
  69. /*
  70.  * Deliver the prototype node for the given symbol.
  71.  */
  72.  
  73. Visible node
  74. gram(sym)
  75.     register int sym;
  76. {
  77.     Assert(sym == 0 || sym > 0 && sym < TABLEN && table[sym].r_symbol);
  78.     return table[sym].r_node;
  79. }
  80.  
  81. #ifdef SAVEBUF
  82.  
  83. /*
  84.  * Deliver the name of a symbol.
  85.  */
  86.  
  87. Visible string
  88. symname(sym)
  89.     int sym;
  90. {
  91.     static char buf[20];
  92.  
  93.     if (sym >= 0 && sym < TABLEN && table[sym].r_name)
  94.         return table[sym].r_name;
  95.     sprintf(buf, "%d", sym);
  96.     return buf;
  97. }
  98.  
  99.  
  100. /*
  101.  * Find the symbol corresponding to a given name.
  102.  * Return -1 if not found.
  103.  */
  104.  
  105. Visible int
  106. nametosym(str)
  107.     register string str;
  108. {
  109.     register int sym;
  110.     register string name;
  111.  
  112.     for (sym = 0; sym < TABLEN; ++sym) {
  113.         name = table[sym].r_name;
  114.         if (name && Strequ(name, str))
  115.             return sym;
  116.     }
  117.     return -1;
  118. }
  119.  
  120. #endif SAVEBUF
  121.  
  122. /*
  123.  * Test whether `sym' may replace the node in the path `p'.
  124.  */
  125.  
  126. Visible bool
  127. allowed(p, sym)
  128.     register path p;
  129.     register int sym;
  130. {
  131.     register path pa = parent(p);
  132.     register int ich = ichild(p);
  133.     register int sympa = pa ? symbol(tree(pa)) : Rootsymbol;
  134.  
  135.     Assert(sympa >= 0 && sympa < TABLEN && ich > 0 && ich <= MAXCHILD);
  136.     return isinclass(sym, table[sympa].r_class[ich-1]);
  137. }
  138.  
  139.  
  140. /*
  141.  * Initialize (and verify) the grammar table.
  142.  */
  143.  
  144. Visible Procedure
  145. initgram()
  146. {
  147.     register int sym;
  148.     register int nch;
  149.     register struct classinfo **cp;
  150.     register struct classinfo *sp;
  151.     node ch[MAXCHILD];
  152.  
  153. #ifndef NDEBUG
  154.     if (dflag)
  155.         fprintf(stderr, "*** initgram();\n\r");
  156. #endif NDEBUG
  157.     /* Set the node pointers in the table and check the representations.
  158.        The code assumes Optional and Hole are the last
  159.        symbols in the table, i.e. the first processed by the loop. */
  160.  
  161.     for (sym = TABLEN-1; sym >= 0; --sym) {
  162.         if (table[sym].r_symbol != sym) {
  163.             if (sym != Hole && sym != Optional && table[sym].r_symbol == 0)
  164.                 continue; /* Disabled table entry */
  165.             syserr("initgram: table order (%s=%d, should be %d)",
  166.                 table[sym].r_name, table[sym].r_symbol, sym);
  167.         }
  168.         cp = table[sym].r_class;
  169.         for (nch = 0; nch < MAXCHILD && (sp = cp[nch]); ++nch)
  170.             ch[nch] =
  171.                 table[sp->c_class[0] == Optional ?
  172.                     Optional : Hole].r_node;
  173.         table[sym].r_node = newnode(nch, sym, ch);
  174.         fix((value) table[sym].r_node);
  175.     }
  176.  
  177.     initcodes();
  178. #ifdef USERSUGG
  179.     initclasses();
  180. #endif USERSUGG
  181. }
  182.  
  183.  
  184. #ifdef USERSUGG
  185.  
  186. /*
  187.  * Add built-in commands to the suggestion tables.
  188.  */
  189.  
  190. Hidden Procedure
  191. initclasses()
  192. {
  193.     register int i;
  194.     register int j;
  195.     register struct table *tp;
  196.  
  197.     for (i = 0; i < TABLEN; ++i) {
  198.         tp = &table[i];
  199.         if (tp->r_symbol != i || i == Suggestion)
  200.             continue; /* Dead entry */
  201.         for (j = 0; j < MAXCHILD && tp->r_class[j]; ++j) {
  202.             if (isinclass(Suggestion, tp->r_class[j]))
  203.                 makesugg(tp->r_class[j]->c_class);
  204.         }
  205.     }
  206. }
  207.  
  208.  
  209. /*
  210.  * Extract suggestions from class list.
  211.  */
  212.  
  213. Hidden Procedure
  214. makesugg(cp)
  215.     classptr cp;
  216. {
  217.     struct table *tp;
  218.     string *rp;
  219.     char buffer[1000];
  220.     string bp;
  221.     string sp;
  222.     int i;
  223.     int nch;
  224.  
  225.     for (; *cp; ++cp) {
  226.         if (*cp >= TABLEN || *cp < 0)
  227.             continue;
  228.         tp = &table[*cp];
  229.         rp = tp->r_repr;
  230.         if (rp[0] && isupper(rp[0][0])) {
  231.             bp = buffer;
  232.             nch = nchildren(tp->r_node);
  233.             for (i = 0; i <= nch; ++i) {
  234.                 if (rp[i]) {
  235.                     for (sp = rp[i]; *sp >= ' '; ++sp)
  236.                         *bp++ = *sp;
  237.                 }
  238.                 if (i < nch && !isinclass(Optional, tp->r_class[i]))
  239.                     *bp++ = '?';
  240.             }
  241.             if (bp > buffer) {
  242.                 *bp = 0;
  243.                 addsugg(buffer, Yes);
  244.             }
  245.         }
  246.     }
  247. }
  248.  
  249. #endif USERSUGG
  250.  
  251.  
  252. /*
  253.  * Compaction scheme for characters to save space in grammar tables
  254.  * by combining characters with similar properties (digits, l.c. letters).
  255.  */
  256.  
  257. #define RANGE 128 /* ASCII characters are in {0 .. RANGE-1} */
  258.  
  259. Visible char code_array[RANGE];
  260. Visible char invcode_array[RANGE];
  261. Visible int lastcode;
  262.  
  263. Hidden Procedure
  264. initcodes()
  265. {
  266.     register int c;
  267.  
  268.     code_array['\n'] = ++lastcode;
  269.     invcode_array[lastcode] = '\n';
  270.     for (c = ' '; c <= '0'; ++c) {
  271.         code_array[c] = ++lastcode;
  272.         invcode_array[lastcode] = c;
  273.     }
  274.     for (; c <= '9'; ++c)
  275.         code_array[c] = lastcode;
  276.     for (; c <= 'a'; ++c) {
  277.         code_array[c] = ++lastcode;
  278.         invcode_array[lastcode] = c;
  279.     }
  280.     for (; c <= 'z'; ++c)
  281.         code_array[c] = lastcode;
  282.     for (; c < RANGE; ++c) {
  283.         code_array[c] = ++lastcode;
  284.         invcode_array[lastcode] = c;
  285.     }
  286. }
  287.  
  288.  
  289. /*
  290.  * Set the root of the grammar to the given symbol.  It must exist.
  291.  */
  292.  
  293. Visible Procedure
  294. setroot(name)
  295.     string name;
  296. {
  297.     register int k;
  298.     register int i;
  299.  
  300.     for (k = 1; k < TABLEN; ++k) {
  301.         if (table[k].r_name && Strequ(name, table[k].r_name)) {
  302.             table[Rootsymbol].r_symbol = table[k].r_symbol;
  303.             table[Rootsymbol].r_name = table[k].r_name;
  304.             for (i = 0; i < MAXCHILD; ++i) {
  305.                 table[Rootsymbol].r_repr[i] = table[k].r_repr[i];
  306.                 table[Rootsymbol].r_class[i] = table[k].r_class[i];
  307.             }
  308.             table[Rootsymbol].r_repr[i] = table[k].r_repr[i];
  309.             table[Rootsymbol].r_node = table[k].r_node;
  310.             table[Rootsymbol].r_symbol = Rootsymbol;
  311.             return;
  312.         }
  313.     }
  314.     syserr("Can't set root of grammar to <%s>", name);
  315. }
  316.  
  317.  
  318. /*
  319.  * The remainder of this file is specific for the currently used grammar.
  320.  */
  321.  
  322.  
  323. #include "boot.h" /* Has static data, so should be included only once! */
  324. #include "syms.h"
  325.  
  326. Visible struct table *table = b_grammar;
  327.  
  328.  
  329. /*
  330.  * Table indicating which symbols are used to form lists of items.
  331.  * Consulted via predicate 'issublist' in "gram.c".
  332.  */
  333.  
  334. Hidden classelem Asublists[] = {
  335.     E_plus, F_e_plus, 
  336.     And, And_kw, Or, Or_kw,
  337.     0,
  338. };
  339.  
  340. Hidden struct classinfo sublists[] = {Asublists};
  341.  
  342.  
  343. /*
  344.  * Predicate telling whether two symbols can form lists together.
  345.  * This is important for list whose elements must alternate in some
  346.  * way, as is the case for [KEYWORD [expression] ]*.
  347.  *
  348.  * This code must be in this file, otherwise the names and values
  349.  * of the symbols would have to be made public.
  350.  */
  351.  
  352. Visible bool
  353. samelevel(sym, sym1)
  354.     register int sym;
  355.     register int sym1;
  356. {
  357.     register int zzz;
  358.  
  359.     if (sym1 == sym)
  360.         return Yes;
  361.     if (sym1 < sym)
  362.         zzz = sym, sym = sym1, sym1 = zzz; /* Ensure sym <= sym1 */
  363.     /* Now always sym < sym1 */
  364.     return sym == Kw_plus && sym1 == E_plus
  365.         || sym == F_kw_plus && sym1 == F_e_plus
  366.         || sym == And && sym1 == And_kw
  367.         || sym == Or && sym1 == Or_kw;
  368. }
  369.  
  370.  
  371. /*
  372.  * Predicate to tell whether a symbol can form chained lists.
  373.  * By definition, all right-recursive symbols can do so;
  374.  * in addition, those listed in the class 'sublists' can do
  375.  * it, too (this is used for lists formed of alternating members
  376.  * such as KW expr KW ...).
  377.  */
  378.  
  379. Visible bool
  380. issublist(sym)
  381.     register int sym;
  382. {
  383.     register int i;
  384.     register string repr;
  385.  
  386.     Assert(sym < TABLEN);
  387.     if (isinclass(sym, sublists))
  388.         return Yes;
  389.     repr = table[sym].r_repr[0];
  390.     if (Fw_positive(repr))
  391.         return No;
  392.     for (i = 0; i < MAXCHILD && table[sym].r_class[i]; ++i)
  393.         ;
  394.     if (i <= 0)
  395.         return No;
  396.     repr = table[sym].r_repr[i];
  397.     if (!Fw_zero(repr))
  398.         return No;
  399.     return isinclass(sym, table[sym].r_class[i-1]);
  400. }
  401.